package workflow

import (
	"encoding/json"
	"project-info/src/constants"
	"project-info/src/handle/response"
	"project-info/src/lib"
	"project-info/src/model"
	"project-info/src/service"
)

// ApproveWorkflowNode 审批节点
func ApproveWorkflowNode(c *lib.GinContext) error {
	var req ApproveWorkflowReq
	if err := c.Bind(&req); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}
	req.ApproveType = constants.ApproveTypeComplete
	return processNode(c, req)
}

// RejectWorkflowNode 拒绝节点
func RejectWorkflowNode(c *lib.GinContext) error {
	var req ApproveWorkflowReq
	if err := c.Bind(&req); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}
	req.ApproveType = constants.ApproveTypeReject
	return processNode(c, req)
}

// CommentWorkflowNode 评论节点
func CommentWorkflowNode(c *lib.GinContext) error {
	var req ApproveWorkflowReq
	if err := c.Bind(&req); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}
	req.ApproveType = constants.ApproveTypeComment
	return processNode(c, req)
}

// processNode 处理节点
func processNode(c *lib.GinContext, req ApproveWorkflowReq) error {
	// 查找node
	var nodeDb *model.Node
	result := model.DB().Where("id = ?", req.NodeId).First(&nodeDb)
	if result.Error != nil {
		c.Logger().Error(result.Error.Error())
		return response.JsonFail(c, "未找到节点")
	}

	if nodeDb.Type != 1 {
		return response.JsonFail(c, "当前节点不是审批节点")
	}

	token := lib.JwtParse(c)
	if value, ok := c.Get(NeedPermissionJudge); ok {
		if b, okBool := value.(bool); okBool && b {
			roleIds, _ := service.GetRoleIdsByUserId(c, token.UserId)
			// 需要进行权限判断
			var count int64
			model.DB().Model(&model.NodeAssignee{}).Where("workflow_instance_id = ? and node_id = ? and ((target_id = ? and type = 1) or (target_id in ? and type = 2))", nodeDb.WorkflowInstanceId, nodeDb.Id, token.UserId, roleIds).Count(&count)
			if count == 0 {
				return response.JsonFail(c, "当前用户没有权限审批")
			}
		}
	}

	// 查找workflowInstance
	var workflowInstance *model.WorkflowInstance
	result = model.DB().Where("id = ?", nodeDb.WorkflowInstanceId).First(&workflowInstance)
	if result.Error != nil {
		c.Logger().Error(result.Error.Error())
		return response.JsonFail(c, "未找到工作流实例")
	}

	var childNode *Node
	err := json.Unmarshal(nodeDb.ChildNode, &childNode)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "解析子节点失败")
	}

	var conditionNodes []*Node
	err = json.Unmarshal(nodeDb.ConditionNodes, &conditionNodes)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "解析条件节点失败")
	}

	var parentNodes []Node
	err = json.Unmarshal(nodeDb.ParentNodes, &parentNodes)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "解析父节点失败")
	}

	node := Node{
		WorkflowInstanceId: nodeDb.WorkflowInstanceId,
		NodeName:           nodeDb.NodeName,
		Type:               nodeDb.Type,
		ExamineMode:        nodeDb.ExamineMode,
		ChildNode:          childNode,
		ConditionNodes:     conditionNodes,
		Condition:          nodeDb.Condition,
	}

	switch req.ApproveType {
	case constants.ApproveTypeComplete:
		// 同意
		err = completeNode(c, node, parentNodes, workflowInstance, nodeDb, token, req.Comment)
		if err != nil {
			c.Logger().Error(err.Error())
			return response.JsonFail(c, "审批失败")
		}
	case constants.ApproveTypeReject:
		// 拒绝
		err = rejectNode(c, node, workflowInstance, nodeDb, token, req.Comment)
		if err != nil {
			c.Logger().Error(err.Error())
			return response.JsonFail(c, "拒绝失败")
		}
	case constants.ApproveTypeComment:
		// 评论
		err = commentNode(c, workflowInstance, nodeDb, node, req, token)
		if err != nil {
			c.Logger().Error(err.Error())
			return response.JsonFail(c, "评论失败")
		}
	default:
		return response.JsonFail(c, "审批类型错误")
	}

	return response.JsonOk(c, "ok")
}

// rejectNode 拒绝节点
func rejectNode(c *lib.GinContext, node Node, workflowInstance *model.WorkflowInstance, nodeDb *model.Node, token *lib.Token, comment string) error {
	// 删除节点指派
	if err := model.DBWithToken(token).Where("workflow_instance_id = ? and node_id = ?", workflowInstance.Id, nodeDb.Id).Delete(&model.NodeAssignee{}).Error; err != nil {
		c.Logger().Error(err.Error())
		return err
	}

	// 更新节点状态为rejected
	if err := model.DBWithToken(token).Model(&model.Node{}).Where("id = ?", nodeDb.Id).Update("status", constants.NodeStatusReject).Error; err != nil {
		c.Logger().Error(err.Error())
		return err
	}

	// 拒绝节点,更新工作流实例状态为rejected
	if err := model.DBWithToken(token).Model(&model.WorkflowInstance{}).Where("id = ?", workflowInstance.Id).Update("status", constants.WorkflowInstanceStatusReject).Error; err != nil {
		c.Logger().Error(err.Error())
		return err
	}

	// 新增一条操作nodeOperator
	nodeOperator := &model.NodeOperator{
		WorkflowInstanceId:     workflowInstance.Id,
		NodeId:                 nodeDb.Id,
		NodeName:               nodeDb.NodeName,
		Operator:               token.UserName,
		OperatorId:             token.UserId,
		Action:                 constants.NodeActionTypeReject,
		WorkflowInstanceStatus: constants.WorkflowInstanceStatusReject,
	}
	if err := model.DBWithToken(token).Create(&nodeOperator).Error; err != nil {
		c.Logger().Error(err.Error())
		return err
	}

	// 保存节点操作记录
	nodeActionHistory := &model.NodeActionHistory{
		WorkflowInstanceId: workflowInstance.Id,
		NodeId:             nodeDb.Id,
		NodeName:           nodeDb.NodeName,
		NodeType:           node.Type,
		Type:               constants.NodeActionTypeReject, // 拒绝类型
		Comment:            comment,
		ActionInfo:         getOperatorActionInfoJson(token),
	}
	return model.DBWithToken(token).Create(&nodeActionHistory).Error
}

// commentNode 评论节点
func commentNode(c *lib.GinContext, workflowInstance *model.WorkflowInstance, nodeDb *model.Node, node Node, req ApproveWorkflowReq, token *lib.Token) error {
	// 新增一条操作nodeOperator
	nodeOperator := &model.NodeOperator{
		WorkflowInstanceId:     workflowInstance.Id,
		NodeId:                 nodeDb.Id,
		NodeName:               nodeDb.NodeName,
		Operator:               token.UserName,
		OperatorId:             token.UserId,
		Action:                 constants.NodeActionTypeComment,
		WorkflowInstanceStatus: constants.WorkflowInstanceStatusApproving,
	}
	if err := model.DBWithToken(token).Create(&nodeOperator).Error; err != nil {
		return err
	}

	nodeActionHistory := &model.NodeActionHistory{
		WorkflowInstanceId: workflowInstance.Id,
		NodeId:             nodeDb.Id,
		NodeName:           nodeDb.NodeName,
		NodeType:           node.Type,
		Type:               constants.NodeActionTypeComment, // 评论类型
		Comment:            req.Comment,
		ActionInfo:         getOperatorActionInfoJson(token),
	}
	return model.DBWithToken(token).Create(&nodeActionHistory).Error
}

// TransferWorkflowNode 转让节点
func TransferWorkflowNode(c *lib.GinContext) error {
	var req TransferWorkflowReq
	if err := c.Bind(&req); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	// 查找woriflowInstance
	var workflowInstance *model.WorkflowInstance
	result := model.DB().Where("id = ?", req.WorkflowInstanceId).First(&workflowInstance)
	if result.Error != nil {
		c.Logger().Error(result.Error.Error())
		return response.JsonFail(c, "未找到工作流实例")
	}

	// 查找节点
	var nodeDb *model.Node
	result = model.DB().Where("id = ?", workflowInstance.CurrentNodeId).First(&nodeDb)
	if result.Error != nil {
		c.Logger().Error(result.Error.Error())
		return response.JsonFail(c, "未找到节点")
	}

	token := lib.JwtParse(c)
	fromNodeAssignees, err := findUserMapNodeAssignee(c, token.UserId, nodeDb)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "转让失败,未找到用户对应审批权限")
	}

	// 需要将fromNodeAssignees中的审批权限转让给req.NodeUsers
	var toAssignees []model.NodeAssignee
	for _, nodeUser := range req.NodeUserList {
		toAssignees = append(toAssignees, model.NodeAssignee{
			WorkflowInstanceId: workflowInstance.Id,
			NodeId:             nodeDb.Id,
			TargetId:           nodeUser.TargetId,
			Name:               nodeUser.Name,
			Type:               nodeUser.Type,
		})
	}

	// 添加节点操作记录
	actionInfo := map[string]interface{}{
		"fromAssignees": fromNodeAssignees,
		"toAssignees":   toAssignees,
		"reason":        req.Reason,
		"operator":      transOperators(token),
	}
	actionInfoJson, _ := json.Marshal(actionInfo)
	nodeActionHistory := &model.NodeActionHistory{
		WorkflowInstanceId: workflowInstance.Id,
		NodeId:             nodeDb.Id,
		NodeName:           nodeDb.NodeName,
		NodeType:           nodeDb.Type,
		Type:               constants.NodeActionTypeTransfer, // 转让类型
		ActionInfo:         actionInfoJson,
	}

	// 保存节点操作记录
	if err := model.DBWithToken(token).Create(&nodeActionHistory).Error; err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "转让失败")
	}

	// 转让节点审批权限到请求的nodeUsers
	if fromNodeAssignees != nil && len(fromNodeAssignees) != 0 {
		if err := model.DB().Delete(&fromNodeAssignees).Error; err != nil {
			c.Logger().Error(err.Error())
			return response.JsonFail(c, "转让失败")
		}
	}

	if err := model.DB().Create(&toAssignees).Error; err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "转让失败")
	}
	return response.JsonOk(c, "转让成功")
}

func findUserMapNodeAssignee(c *lib.GinContext, userId uint64, nodeDb *model.Node) ([]model.NodeAssignee, error) {
	roleIds, err := service.GetRoleIdsByUserId(c, userId)
	if err != nil {
		c.Logger().Error(err.Error())
		return nil, err
	}

	// 检查用户的审批权限时来自哪些用户id和角色id的节点审批权限
	var fromNodeAssignees []model.NodeAssignee
	result := model.DB().Where("node_id = ? and ((type = ? and target_id = ?) or (type = ? and target_id in ?))", nodeDb.Id, constants.NodeAssigneeTypeUser, userId, constants.NodeAssigneeTypeRole, roleIds).Find(&fromNodeAssignees)
	if result.Error != nil {
		c.Logger().Error(result.Error.Error())
		return nil, err
	}
	return fromNodeAssignees, nil
}
